package projects.jnurse.ioc.core.reflection;

import projects.jnurse.ioc.annotations.Fill;
import projects.jnurse.ioc.core.DependencyStore;

import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.Field;

/**
 * Created by Adil Naji.
 * User: XP-170708
 * Date: 18 nov. 2008
 * Time: 18:30:39
 */
public class FieldResolver implements Resolver {

    Class annotation;
    String attr;
    //String value;
    //boolean keep2DRelations;
    //Class clazz;

    public FieldResolver annotated(Class annotation, String attr) {
        this.annotation = annotation;
        this.attr = attr;
        //keep2DRelations = true;
        return this;
    }

    public List<Field> in(final Object instance) {
        Scanner<Field> scanner = new Scanner<Field>() {
            //TODO passer un FieldVisitor en param, ki s'appliquera sur chaque field
            public Result<Field> scan(Class clazz) {
                Result<Field> result = new Result<Field>();
                result.addResult(clazz.getDeclaredFields());
                return result;
            }
        };

        Result<Field> result = scanner.scan(instance.getClass());

        Filter<Field> filter = new Filter<Field>() {

            List<ReflectionObserver<Field>> listerners = new ArrayList<ReflectionObserver<Field>>();

            {
                addListener(new ReflectionObserver<Field>() {
                    public void onFound(Field field) {
                        field.setAccessible(true);
                        Fill fill = field.getAnnotation(Fill.class);
                        if (fill != null) {
                            Object ref = DependencyStore.instance.resolve(fill.by());

                            try { field.set(instance, ref); }
                            catch(Exception e) { e.printStackTrace(); }
                        }
                    }
                });
            }

            public Result<AnnotationResult> filter(Result<Field> fieldResult, FilteringCondition condition) {
                List<Field> fields = fieldResult.getResultList();
                fieldResult.clear();

                Result<AnnotationResult> result = new Result<AnnotationResult>();
                for (Field field: fields) {
                    //if (condition.test(field)) {
                    if (true) {
                        //AnnotationResult<Field> annotationResult = new AnnotationResult<Field>(field);
                        //annotationResult.addAttribute();
                        //result.addResult(annotationResult);
                        for(ReflectionObserver<Field> listener: listerners)
                            listener.onFound(field);
                    }
                }
                return result;
            }

            public void addListener(ReflectionObserver<Field> listener) {
                listerners.add(listener);
            }
        };

        Filter.FilteringCondition condition = new Filter.FilteringCondition() {
            public boolean test(Object... args) {
                Field field = (Field)args[0];
                Object anno = field.getAnnotation(annotation);
                return anno != null;
            }
        };

        return filter.filter(result, condition).getResultList();
    }
}
